package com.dreamscope.login;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

import javax.servlet.http.HttpServletRequest;

/**
 * PseudoSessionBean is responsible for Handling User Sessions
 * It provides Session Tracking Mechanism and is more reliable 
 * over conventional methods. 
 * 
 * @author Akhil Jain
 * Aug 10, 2007
 */
public class PseudoSessionBean {
	/**
	 * Directory path where all the session files will be stored
	 */
	public String path = "C:\\SessionDir\\";
	
	/**
	 * Time that has to pass after the last request of a user before the session is invalidated.
	 */
	public long timeOut = 5* 60 * 1000; //in ms (5 minutes)
	
	/**
	 * Default Constructor
	 *
	 */
	public PseudoSessionBean() {
	
	}
	
	/**
	 * This method should be invoked at the begining of each JSP page for URL rewriting 
	 * It assignes a new fresh Session Identifier when a new user visits the page first time.
	 * It checks the validity of the Session Identifier carried in the URL.
	 * If the Session Identifier is not valid or has expired, it will return a new Session Identifier.
	 *  
	 * @param request
	 * @return
	 */
	public String getSessionID(HttpServletRequest request){
		String sessionId = request.getParameter("sessionId");
		System.out.println("Session Id generated: "+sessionId);
		
		//To identify whether session is valid or not
		boolean validSessionIdFound = false;
		
		//server time when the request occurs. will be used to validity of user session.
		long now = System.currentTimeMillis();
		
		/*	check sessionId's validity, by checking
		 *	1. A valid session identifier must have a valid text file with its name
		 *	2. Last modify time of the text file should not be longer than the timeout.
		 *	3. If a corresponding text file is found but has expired the old text file is deleted.
		 *	4. If the text file of a valid session identifier is found, its last modified time is updated, reflecting the current access to it.
		 */ 
		if(sessionId!=null){
			File f = new File(path + sessionId);
			if (f.exists()){
				 if (f.lastModified() + timeOut > now) {  // session valid
				 /*with setLastModified, if the file is locked by other apps
				   there won't be any exception but the file data does not change */
					 f.setLastModified(now);
					 validSessionIdFound = true;
					 return sessionId;
				 }else{// session expired 
				 // delete the file
				     f.delete();
				 }
			} // End if (f.exists)
		} // End if (sessionId!=null)
		
		
		/*If a valid session identifier is not found, a session identifier is generated and a corresponding text file is created.*/
		if (!validSessionIdFound){
			  sessionId = Long.toString(now);
			  //create a file
			  File f = new File(path + sessionId);
			  try{
				  f.createNewFile();
			  }catch (IOException ioe) {}
		}//End of if !validSessionIdFound
		
		/* A very simple random generator has been created by converting the system time (current) into the session identifier.
		 * More robust algoes should be used to generate session identifier.
		 */
		sessionId = Long.toString(now);
		return sessionId;
	}
	
	/**
	 * Used to store a String value associated with a String called name.
	 * It is assumed that the getSessionID method has been invoked before 
	 * this method is called and so a validated session identifier is certain to exist. 
	 * The session identifier passed to this method will not be validated again.
	 * 
	 * It does two things
	 * 1. If the String value is associated with a name that does not yet exist, 
	 * 	  the new name-value pair will be appended to the text file.
	 * 2. If the String value is associated with a name that already exists, 
	 *    the old value is replaced by the new value.
	 *
	 * 
	 * It first tries to find the corresponding session text file. 
	 * If the file does not exist, the method will return without doing anything. 
	 * If the session text file is found, the method will read every line of 
	 * the text file and compare the line with name. If the line begins 
	 * with name followed by a white space, it means the name already exists 
	 * and the value is replaced. If the comparison does not result in a match, 
	 * the line will simply be copied to the temporary file.
	 *
	 */
	public void setValue(String sessionId, String name, String value){
		try{		  
			  System.out.println("Writing sessionId file: "+path + sessionId); 
			  FileReader fr = new FileReader(path + sessionId);
			  BufferedReader br = new BufferedReader(fr);
	
			  FileWriter fw = new FileWriter(path + sessionId + ".tmp");
			  BufferedWriter bw = new BufferedWriter(fw);
	
			  String s;
			  while ((s = br.readLine()) != null)
				  if (!s.startsWith(name + " ")) {
					  	bw.write(s); //write the line to the file
					  	bw.newLine();
				  }
			 
			  bw.write(name + " " + value);
		      bw.newLine();
	
		      bw.close();
		      br.close();
		      fw.close();
		      br.close();
		      
		      /* After all lines are copied into the temporary files, 
			   * the original session text file is deleted and the temporary file is renamed the session text file.
			   */
			  File f = new File(path + sessionId + ".tmp");
			  File dest = new File(path + sessionId);
			  dest.delete();
			  if(f.renameTo(dest))
				  System.out.println("File Name changed Successfully!");
			  
			  System.out.println("SessionId set at first page : "+sessionId);
		}
		catch (FileNotFoundException e) {}
		catch (IOException e) { System.out.println(e.toString());}
		
		
	}
	
	/**
	 * This method allows you to retrieve values that you have stored in the pseudo session.
	 * This method also requires you to pass a valid session identifier. 
	 * The session identifier won't be checked again for validity. 
	 * The second argument is the name that the value you want to retrieve is associated with. 
	 * The getValue method returns the value associated with name.
	 * 
	 * It basically finds the session text file and reads it line-by-line until it finds a match with name. 
	 * When a match is found, the method returns the value; if a match is not found, it returns null.
	 * 
	 * @param sessionId
	 * @param name
	 * @return
	 */
	public String getValue(String sessionId, String name){
	    try {
	    	System.out.println("SessionId trying at second page : "+sessionId);
	    	FileReader fr = new FileReader(path + sessionId);
	        BufferedReader br = new BufferedReader(fr);
	        String s;
	        while ((s = br.readLine()) != null)
	        	if (s.startsWith(name + " ")) {
	        		br.close();
	        		fr.close();
	        		return s.substring(name.length());
	        	}
	        br.close();
	        fr.close();
	      }
	      catch (FileNotFoundException e) {}
	      catch (IOException e) {}
	      return null;
	}
	
	/**
	 * This method deletes text files associated with sessions that have expired.
	 * User can call this method , either at the end of the JSP file (but will consume unneccessary CPU time),
	 * but convinient way, if traffic is heavy. Otherwise.
	 * 
	 * TODO: write a background thread which can be invoked at a particular time in a day 
	 * to free-up the memory with expired session files.
	 *
	 */
	public void deleteAllInvalidSessions(){
		
		//reads all session text filenames into a String array called files.
		File dir = new File(path); 
		String[] files = dir.list();
		
		/* It then needs to determine whether or not a session has expired by 
		 * comparing the text file's last modified time with the System's current
		 * time after being offset by timeOut. The long variable now is used to 
		 * store the System's current time.
		 */
		long now = System.currentTimeMillis();

		/*It then loops through the String array files and reads each text file's 
		 *lastModified property. All text files associated with expired sessions will be deleted.
		 */
		for(int i=0; i<files.length; i++) {
			File f = new File(path + files[i]);
			if (f.lastModified() + timeOut > now)
			    f.delete();  // delete expired session text file.
		}
		
		
	}
	
}
